/**
 * 一个简单的路由拦截器
 * @author 陈老师儿~
 * @mobile 18560000860
 */
import pagesJson from "@/pages.json";
export default {
    install(app, options) {
        // 默认配置
        let _config = {
            /**
             * 前置路由拦截函数
             * @param {Object} params 跳转参数，其中，另外增加了3个字段：
             *                        1. fromPageJsonConfig: 来源页面的配置信息
             *                        2. toPageJsonCinfig: 目标页面的配置信息
             *                        3. navigateType: 跳转类型，对应值：navigateTo、redirectTo、reLaunch、switchTab、navigateBack
             * @returns {Boolean} true: 继续执行跳转，false: 终止跳转
             */
            before: null,

            /**
             * 后置路由拦截器函数
             * @param {Object} pageJsonConfig 当前页面在 pages.json 中的配置信息
             */
            after: null,
        };

        // 合并配置
        _config = objectDeepMerge(_config, options);

        /**
         * 设置配置
         * @param {Object} config 配置数据
         */
        function setConfig(config = {}) {
            _config = objectDeepMerge(_config, config);
        }

        // uni-app 路由
        const uniNavigateTo = uni.navigateTo;
        const uniRedirectTo = uni.redirectTo;
        const uniReLaunch = uni.reLaunch;
        const uniSwitchTab = uni.switchTab;
        const uniNavigateBack = uni.navigateBack;

        /**
         * 重写 uni-app 路由
         */
        uni.navigateTo = (params = {}) => {
            params.fromPageJsonConfig = getCurrentPageJsonConfig();
            params.toPageJsonCinfig = getToPageJsonConfig(params.url);
            params.navigateType = "navigateTo";
            if (beforeRouteTo(params)) uniNavigateTo(params);
        };

        uni.redirectTo = (params = {}) => {
            params.fromPageJsonConfig = getCurrentPageJsonConfig();
            params.toPageJsonCinfig = getToPageJsonConfig(params.url);
            params.navigateType = "redirectTo";
            if (beforeRouteTo(params)) uniRedirectTo(params);
        };

        uni.reLaunch = (params = {}) => {
            params.fromPageJsonConfig = getCurrentPageJsonConfig();
            params.toPageJsonCinfig = getToPageJsonConfig(params.url);
            params.navigateType = "reLaunch";
            if (beforeRouteTo(params)) uniReLaunch(params);
        };

        uni.switchTab = (params = {}) => {
            params.fromPageJsonConfig = getCurrentPageJsonConfig();
            params.toPageJsonCinfig = getToPageJsonConfig(params.url);
            params.navigateType = "switchTab";
            if (beforeRouteTo(params)) uniSwitchTab(params);
        };

        uni.navigateBack = (params = {}) => {
            params.fromPageJsonConfig = getCurrentPageJsonConfig();
            params.toPageJsonCinfig = getPrevPageJsonConfig();
            params.navigateType = "navigateBack";
            if (beforeRouteTo(params)) uniNavigateBack(params);
        };

        /**
         * 调用前置路由拦截函数
         */
        function beforeRouteTo(params = {}) {
            if (isFunction(_config.before)) return _config.before(params);
            return true;
        }

        /**
         * 刷新页面
         */
        function refresh() {
            // H5
            // #ifdef H5
            window.location.reload();
            return;
            // #endif

            const pages = getCurrentPages();
            const page = pages[pages.length - 1];
            if (!page) return;

            // path
            let path = page.route;
            if (!path.startsWith("/")) path = `/${path}`;

            // query
            const query = page.options;
            const queryString = objectToQueryString(query);

            // 是否是 tabbar 页面
            const isTabbarPage = isTabBarPage(path);

            // 带参数的路径
            const fullPath = queryString ? `${path}?${queryString}` : path;

            // tabbar 页面使用 reLaunch 实现刷新
            if (isTabbarPage) {
                uni.reLanuch({
                    url: fullPath,
                });
            }

            // 非 tabbar 页面使用 redirectTo 实现刷新
            else {
                uni.redirectTo({
                    url: fullPath,
                });
            }
        }

        /**
         * 将参数对象转换为 url 参数字符串
         */
        function objectToQueryString(obj = {}) {
            const parts = [];
            for (const key in obj) {
                if (obj.hasOwnProperty(key)) {
                    const value = obj[key];
                    const encodedKey = encodeURIComponent(key);
                    const encodedValue = encodeURIComponent(value);
                    parts.push(`${encodedKey}=${encodedValue}`);
                }
            }
            return parts.join("&");
        }

        /**
         * 获取 URL 问号之前的部分
         * @param {String} url URL 字符串
         * @returns {String} 返回URL 主要部分（问号之前的部分）字符串
         */
        function getUrlBeforeQuestionMark(url = "") {
            const questionIndex = url.indexOf("?");
            if (questionIndex === -1) return url;
            return url.slice(0, questionIndex);
        }

        // 获取当前页面在 pages.json 中定义的数据
        function getCurrentPageJsonConfig() {
            const pages = getCurrentPages();
            const page = pages[pages.length - 1];
            if (!page) return null;
            const route = page?.route;
            return getPageJsonConfig(route);
        }

        // 获取目标页面在 pages.json 中定义的数据
        function getToPageJsonConfig(url = "") {
            const baseURL = getUrlBeforeQuestionMark(url);
            return getPageJsonConfig(baseURL);
        }

        // 获取上一页在 pages.json 中定义的数据
        function getPrevPageJsonConfig() {
            const pages = getCurrentPages();
            const page = pages[pages.length - 2];
            if (!page) return null;
            const route = page?.route;
            return getPageJsonConfig(route);
        }

        /**
         * 获取页面在 pages.json 中定义的数据
         */
        function getPageJsonConfig(url = "") {
            // 未定义
            if (!url) return null;

            // 先从主包数据中获取页面数据
            const mainPages = pagesJson?.pages || [];

            let pageData = mainPages.find((item) => {
                // 比较路径是否相同
                return isSamePagePath(url, item.path);
            });

            // 找到了，直接返回
            if (pageData) return pageData;

            // 没找到，再从分包数据中获取页面数据
            const subPackages = pagesJson?.subPackages || [];
            const subPackagesLength = subPackages.length;

            outerloop: for (let i = 0; i < subPackagesLength; i++) {
                const subPackage = subPackages[i];
                const subPackageRoot = subPackage?.root || "";
                const subPackagePages = subPackage?.pages || [];
                const subPackagePagesLength = subPackagePages.length;

                for (let j = 0; j < subPackagePagesLength; j++) {
                    const subPackagePage = subPackagePages[j];
                    const subPackagePagePath = subPackagePage?.path;
                    const subPackagePageFullPath = subPackageRoot + "/" + subPackagePagePath;

                    // 比较路径是否相同
                    if (isSamePagePath(url, subPackagePageFullPath)) {
                        pageData = subPackagePage;
                        break outerloop;
                    }
                }
            }

            return pageData;
        }

        // 判断是否同一个页面路径
        function isSamePagePath(url1 = "", url2 = "") {
            // 统一成加 "/" 开头的路径
            if (!url1.startsWith("/")) {
                url1 = `/${url1}`;
            }

            if (!url2.startsWith("/")) {
                url2 = `/${url2}`;
            }

            return url1 === url2;
        }

        // 判断页面是否是Tabbar页面
        function isTabBarPage(url = "") {
            // 未传url就判断当前页面
            if (!url) {
                url = getCurrentPageJsonConfig()?.path || "";
            }

            // TabBar 页面数据
            const tabBarList = pagesJson?.tabBar?.list || [];
            let pageData = tabBarList.find((item) => {
                // 比较路径是否相同
                return isSamePagePath(url, item.pagePath);
            });
            return !!pageData;
        }

        /**
         * 验证数据是否是 Array 类型数据
         * @param {Any} variable 要验证的数据
         * @returns {Boolean} true: 是 Array 类型数据；false: 不是 Array 类型数据；
         */
        function isArray(variable) {
            return Array.isArray(variable);
        }

        /**
         * 验证数据是否是 Object 类型数据
         * Tips: 不包括数组、函数、null等
         * @param {Object} variable 要验证的数据
         * @returns {Boolean} true: 是 Object 类型数据；false: 不是 Object 类型数据；
         */
        function isObject(variable) {
            // 排除 null 和非对象类型
            if (variable === null || typeof variable !== "object") return false;

            // 使用 Object.prototype.toString.call 来获取变量的真实类型
            // 注意这里需要排除函数类型，因为函数在JavaScript中也是对象，但通常我们不希望将它们视为普通对象
            return Object.prototype.toString.call(variable) === "[object Object]";
        }

        /**
         * 验证数据是否是 Function 类型数据
         * @param {Any} variable 需要验证的数据
         * @returns {Boolean} true: 是Function 类型数据；false: 不是Function 类型数据；
         */
        function isFunction(variable) {
            return Object.prototype.toString.call(variable) === "[object Function]";
        }

        /**
         * 深度合并两个对象
         * @param {Object} object1 对象一
         * @param {Object} object2 对象二
         * @returns {Object} 合并后的新对象数据，不影响原对象
         */
        function objectDeepMerge(object1, object2) {
            let merged = Object.assign({}, object1);
            for (let key in object2) {
                if (object2.hasOwnProperty(key)) {
                    if (isObject(object2[key]) && !isArray(object2[key])) {
                        if (isObject(merged[key]) && !isArray(merged[key])) {
                            merged[key] = objectDeepMerge(merged[key], object2[key]);
                        } else {
                            merged[key] = Object.assign({}, object2[key]);
                        }
                    } else {
                        merged[key] = object2[key];
                    }
                }
            }
            return merged;
        }

        app.mixin({
            onShow: () => {
                // 获取数据
                const currentPageJsonConfig = getCurrentPageJsonConfig();
                if (isFunction(_config?.after) && currentPageJsonConfig) {
                    _config?.after(currentPageJsonConfig);
                }
            },
        });

        uni.$pureRouter = {
            setConfig,
            refresh,
            getCurrentPageJsonConfig,
            getPrevPageJsonConfig,
            getPageJsonConfig,
            isTabBarPage,
        };
    },
};
